{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "# 5输出解析器\n",
    "\n",
    "语言模型输出文本。但很多时候，您可能希望获得更结构化的信息，而不仅仅是文本回复。这就是输出解析器的用武之地。\n",
    "\n",
    "\n",
    "输出分析器是帮助构建语言模型响应的类。输出分析器必须实现两种主要方法：\n",
    "\n",
    "“获取格式指令”：返回一个字符串的方法，其中包含有关如何格式化语言模型输出的说明。\n",
    "\n",
    "“Parse”：一种接收字符串（假设是来自语言模型的响应）并将其解析为某种结构的方法。\n",
    "\n",
    "然后是一个可选的：\n",
    "\n",
    "“Parse with prompt”：一种方法，它接受一个字符串（假设是来自语言模型的响应）和一个提示（假设是生成此类响应的提示）并将其解析为某种结构。提示主要在 OutputParser 想要以某种方式重试或修复输出时提供，并且需要来自提示的信息才能执行此操作。"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "outputs": [
    {
     "data": {
      "text/plain": "Joke(setup='为什么有的人喜欢吃苹果？', punchline='因为它们是甜甜的！')"
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#这段代码的主要目的是使用一个预训练的语言模型从OpenAI来生成并验证一个笑话。\n",
    "# 导入必要的模块和类\n",
    "from langchain.prompts import PromptTemplate, ChatPromptTemplate, HumanMessagePromptTemplate\n",
    "from langchain.llms import OpenAI\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "from langchain.output_parsers import PydanticOutputParser\n",
    "from pydantic import BaseModel, Field, validator\n",
    "from typing import List\n",
    "\n",
    "# 定义模型名称和温度（影响模型的随机性）\n",
    "model_name = 'text-davinci-003'\n",
    "temperature = 0.0\n",
    "\n",
    "# 初始化OpenAI模型\n",
    "model = OpenAI(model_name=model_name, temperature=temperature)\n",
    "\n",
    "# 定义想要的数据结构，这里是一个笑话的结构，包含设置和冷笑话\n",
    "class Joke(BaseModel):\n",
    "    setup: str = Field(description=\"question to set up a joke\")  # 笑话的设置部分\n",
    "    punchline: str = Field(description=\"answer to resolve the joke\")  # 笑话的冷笑话部分\n",
    "\n",
    "    # 使用Pydantic添加自定义验证逻辑，确保设置部分以问号结束\n",
    "    @validator('setup')\n",
    "    def question_ends_with_question_mark(cls, field):\n",
    "        if field[-1] != '？':\n",
    "            raise ValueError(\"Badly formed question!\")\n",
    "        return field\n",
    "\n",
    "# 设置一个解析器，并将指令注入到提示模板中\n",
    "parser = PydanticOutputParser(pydantic_object=Joke)\n",
    "\n",
    "# 定义提示模板\n",
    "prompt = PromptTemplate(\n",
    "    template=\"Answer the user query.\\n{format_instructions}\\n{query}\\n\",\n",
    "    input_variables=[\"query\"],\n",
    "    partial_variables={\"format_instructions\": parser.get_format_instructions()}\n",
    ")\n",
    "\n",
    "# 定义一个查询，目的是提示语言模型填充上述数据结构\n",
    "joke_query = \"给我用中文讲个笑话.\"\n",
    "\n",
    "# 格式化提示\n",
    "_input = prompt.format_prompt(query=joke_query)\n",
    "\n",
    "# 使用模型生成输出\n",
    "output = model(_input.to_string())\n",
    "\n",
    "# 使用解析器解析输出\n",
    "parser.parse(output)\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T06:36:30.055168100Z",
     "start_time": "2023-08-25T06:36:28.065402700Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 5.1 列表解析器\n",
    "当您想要返回逗号分隔项的列表时，可以使用此输出分析器。"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "outputs": [
    {
     "data": {
      "text/plain": "['草莓', '香草', '抹茶', '巧克力', '杏仁酥']"
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 导入必要的模块和类\n",
    "from langchain.output_parsers import CommaSeparatedListOutputParser\n",
    "from langchain.prompts import PromptTemplate, ChatPromptTemplate, HumanMessagePromptTemplate\n",
    "from langchain.llms import OpenAI\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "\n",
    "# 初始化一个解析由逗号分隔的列表的解析器\n",
    "output_parser = CommaSeparatedListOutputParser()\n",
    "\n",
    "# 获取解析器的格式指令\n",
    "format_instructions = output_parser.get_format_instructions()\n",
    "\n",
    "# 定义提示模板，用于生成关于特定主题的由逗号分隔的列表\n",
    "prompt = PromptTemplate(\n",
    "    template=\"List five {subject}.\\n{format_instructions}\",\n",
    "    input_variables=[\"subject\"],\n",
    "    partial_variables={\"format_instructions\": format_instructions}\n",
    ")\n",
    "\n",
    "# 初始化OpenAI模型，温度设置为0（生成的回答将更加确定，少有随机性）\n",
    "model = OpenAI(temperature=0)\n",
    "\n",
    "# 格式化提示，这里的主题是“ice cream flavors”（冰淇淋口味）\n",
    "_input = prompt.format(subject=\"冰淇淋口味\")\n",
    "\n",
    "# 使用模型生成输出\n",
    "output = model(_input)\n",
    "\n",
    "# 使用解析器解析输出\n",
    "output_parser.parse(output)\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T06:39:28.750884500Z",
     "start_time": "2023-08-25T06:39:27.055757Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 5.2 日期时间解析器\n",
    "\n",
    "此输出解析器显示将LLM输出解析为日期时间格式。"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "outputs": [],
   "source": [
    "# 导入必要的模块和类\n",
    "from langchain.prompts import PromptTemplate\n",
    "from langchain.output_parsers import DatetimeOutputParser\n",
    "from langchain.chains import LLMChain\n",
    "from langchain.llms import OpenAI\n",
    "\n",
    "# 初始化一个日期时间输出解析器\n",
    "output_parser = DatetimeOutputParser()\n",
    "\n",
    "# 定义提示模板，用于引导模型回答用户的问题\n",
    "template = \"\"\"回答用户的问题:\n",
    "\n",
    "{question}\n",
    "\n",
    "{format_instructions}\"\"\"\n",
    "\n",
    "# 使用模板创建一个提示实例\n",
    "prompt = PromptTemplate.from_template(\n",
    "    template,\n",
    "    partial_variables={\"format_instructions\": output_parser.get_format_instructions()},\n",
    ")\n",
    "\n",
    "# 初始化一个LLMChain，它结合了提示和OpenAI模型来生成输出\n",
    "chain = LLMChain(prompt=prompt, llm=OpenAI())\n",
    "\n",
    "# 运行链来获取关于特定问题的答案，这里的问题是“bitcoin是什么时候成立的？”\n",
    "output = chain.run(\"bitcoin是什么时候成立的？用英文格式输出时间\")\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T06:42:06.295645400Z",
     "start_time": "2023-08-25T06:42:04.878647900Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "outputs": [
    {
     "data": {
      "text/plain": "'\\n\\n2009-01-03T18:15:05.000000Z'"
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "output"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T06:42:07.668406700Z",
     "start_time": "2023-08-25T06:42:07.650400200Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "outputs": [
    {
     "data": {
      "text/plain": "datetime.datetime(2009, 1, 3, 18, 15, 5)"
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "output_parser.parse(output)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T06:42:08.823836500Z",
     "start_time": "2023-08-25T06:42:08.757327900Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 5.3 枚举解析器"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "outputs": [],
   "source": [
    "from langchain.output_parsers.enum import EnumOutputParser\n",
    "from enum import Enum\n",
    "\n",
    "\n",
    "class Colors(Enum):\n",
    "    RED = \"red\"\n",
    "    GREEN = \"green\"\n",
    "    BLUE = \"blue\"\n",
    "\n",
    "parser = EnumOutputParser(enum=Colors)\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T09:08:24.620198700Z",
     "start_time": "2023-08-25T09:08:24.572658200Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "outputs": [
    {
     "data": {
      "text/plain": "<Colors.RED: 'red'>"
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "parser.parse(\"red\")"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T09:08:27.665450200Z",
     "start_time": "2023-08-25T09:08:27.642452900Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "outputs": [
    {
     "data": {
      "text/plain": "<Colors.GREEN: 'green'>"
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Can handle spaces\n",
    "parser.parse(\" green\")"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T09:08:32.580198700Z",
     "start_time": "2023-08-25T09:08:32.544196500Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "outputs": [
    {
     "data": {
      "text/plain": "<Colors.BLUE: 'blue'>"
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# And new lines\n",
    "parser.parse(\"blue\\n\")"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T09:09:18.723938200Z",
     "start_time": "2023-08-25T09:09:18.676933600Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "outputs": [
    {
     "ename": "OutputParserException",
     "evalue": "Response 'yellow' is not one of the expected values: ['red', 'green', 'blue']",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mValueError\u001B[0m                                Traceback (most recent call last)",
      "File \u001B[1;32mE:\\pycharmproject\\LangChainStudyProject\\venv\\lib\\site-packages\\langchain\\output_parsers\\enum.py:28\u001B[0m, in \u001B[0;36mEnumOutputParser.parse\u001B[1;34m(self, response)\u001B[0m\n\u001B[0;32m     27\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[1;32m---> 28\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43menum\u001B[49m\u001B[43m(\u001B[49m\u001B[43mresponse\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mstrip\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m     29\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m:\n",
      "File \u001B[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\enum.py:385\u001B[0m, in \u001B[0;36mEnumMeta.__call__\u001B[1;34m(cls, value, names, module, qualname, type, start)\u001B[0m\n\u001B[0;32m    384\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m names \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:  \u001B[38;5;66;03m# simple value lookup\u001B[39;00m\n\u001B[1;32m--> 385\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mcls\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[38;5;21;43m__new__\u001B[39;49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mcls\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mvalue\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    386\u001B[0m \u001B[38;5;66;03m# otherwise, functional API: we're creating a new Enum type\u001B[39;00m\n",
      "File \u001B[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\enum.py:710\u001B[0m, in \u001B[0;36mEnum.__new__\u001B[1;34m(cls, value)\u001B[0m\n\u001B[0;32m    709\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m result \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m \u001B[38;5;129;01mand\u001B[39;00m exc \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[1;32m--> 710\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m ve_exc\n\u001B[0;32m    711\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m exc \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n",
      "\u001B[1;31mValueError\u001B[0m: 'yellow' is not a valid Colors",
      "\nDuring handling of the above exception, another exception occurred:\n",
      "\u001B[1;31mOutputParserException\u001B[0m                     Traceback (most recent call last)",
      "Cell \u001B[1;32mIn[17], line 2\u001B[0m\n\u001B[0;32m      1\u001B[0m \u001B[38;5;66;03m# And raises errors when appropriate\u001B[39;00m\n\u001B[1;32m----> 2\u001B[0m \u001B[43mparser\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mparse\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43myellow\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m)\u001B[49m\n",
      "File \u001B[1;32mE:\\pycharmproject\\LangChainStudyProject\\venv\\lib\\site-packages\\langchain\\output_parsers\\enum.py:30\u001B[0m, in \u001B[0;36mEnumOutputParser.parse\u001B[1;34m(self, response)\u001B[0m\n\u001B[0;32m     28\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39menum(response\u001B[38;5;241m.\u001B[39mstrip())\n\u001B[0;32m     29\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m:\n\u001B[1;32m---> 30\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m OutputParserException(\n\u001B[0;32m     31\u001B[0m         \u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mResponse \u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;132;01m{\u001B[39;00mresponse\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124m is not one of the \u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[0;32m     32\u001B[0m         \u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mexpected values: \u001B[39m\u001B[38;5;132;01m{\u001B[39;00m\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_valid_values\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m\"\u001B[39m\n\u001B[0;32m     33\u001B[0m     )\n",
      "\u001B[1;31mOutputParserException\u001B[0m: Response 'yellow' is not one of the expected values: ['red', 'green', 'blue']"
     ]
    }
   ],
   "source": [
    "# And raises errors when appropriate\n",
    "parser.parse(\"yellow\")"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T09:08:49.429360400Z",
     "start_time": "2023-08-25T09:08:49.309899900Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 5.4 自动修复解析器\n",
    "此输出解析器包装另一个输出解析器，如果第一个输出解析器失败，它会调用另一个 LLM 以修复任何错误。\n",
    "\n",
    "但是除了抛出错误之外，我们还可以做其他事情。具体来说，我们可以将格式错误的输出以及格式化的指令传递给模型，并要求它修复它。"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "outputs": [
    {
     "ename": "OutputParserException",
     "evalue": "Failed to parse Actor from completion {'name': 'Tom Hanks', 'film_names': ['Forrest Gump']}. Got: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mJSONDecodeError\u001B[0m                           Traceback (most recent call last)",
      "File \u001B[1;32mE:\\pycharmproject\\LangChainStudyProject\\venv\\lib\\site-packages\\langchain\\output_parsers\\pydantic.py:28\u001B[0m, in \u001B[0;36mPydanticOutputParser.parse\u001B[1;34m(self, text)\u001B[0m\n\u001B[0;32m     27\u001B[0m     json_str \u001B[38;5;241m=\u001B[39m match\u001B[38;5;241m.\u001B[39mgroup()\n\u001B[1;32m---> 28\u001B[0m json_object \u001B[38;5;241m=\u001B[39m \u001B[43mjson\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mloads\u001B[49m\u001B[43m(\u001B[49m\u001B[43mjson_str\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mstrict\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43;01mFalse\u001B[39;49;00m\u001B[43m)\u001B[49m\n\u001B[0;32m     29\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mpydantic_object\u001B[38;5;241m.\u001B[39mparse_obj(json_object)\n",
      "File \u001B[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\json\\__init__.py:359\u001B[0m, in \u001B[0;36mloads\u001B[1;34m(s, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)\u001B[0m\n\u001B[0;32m    358\u001B[0m     kw[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mparse_constant\u001B[39m\u001B[38;5;124m'\u001B[39m] \u001B[38;5;241m=\u001B[39m parse_constant\n\u001B[1;32m--> 359\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mcls\u001B[39;49m\u001B[43m(\u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mkw\u001B[49m\u001B[43m)\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mdecode\u001B[49m\u001B[43m(\u001B[49m\u001B[43ms\u001B[49m\u001B[43m)\u001B[49m\n",
      "File \u001B[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\json\\decoder.py:337\u001B[0m, in \u001B[0;36mJSONDecoder.decode\u001B[1;34m(self, s, _w)\u001B[0m\n\u001B[0;32m    333\u001B[0m \u001B[38;5;250m\u001B[39m\u001B[38;5;124;03m\"\"\"Return the Python representation of ``s`` (a ``str`` instance\u001B[39;00m\n\u001B[0;32m    334\u001B[0m \u001B[38;5;124;03mcontaining a JSON document).\u001B[39;00m\n\u001B[0;32m    335\u001B[0m \n\u001B[0;32m    336\u001B[0m \u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[1;32m--> 337\u001B[0m obj, end \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mraw_decode\u001B[49m\u001B[43m(\u001B[49m\u001B[43ms\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43midx\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_w\u001B[49m\u001B[43m(\u001B[49m\u001B[43ms\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m0\u001B[39;49m\u001B[43m)\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mend\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    338\u001B[0m end \u001B[38;5;241m=\u001B[39m _w(s, end)\u001B[38;5;241m.\u001B[39mend()\n",
      "File \u001B[1;32m~\\AppData\\Local\\Programs\\Python\\Python310\\lib\\json\\decoder.py:353\u001B[0m, in \u001B[0;36mJSONDecoder.raw_decode\u001B[1;34m(self, s, idx)\u001B[0m\n\u001B[0;32m    352\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[1;32m--> 353\u001B[0m     obj, end \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mscan_once\u001B[49m\u001B[43m(\u001B[49m\u001B[43ms\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43midx\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    354\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mStopIteration\u001B[39;00m \u001B[38;5;28;01mas\u001B[39;00m err:\n",
      "\u001B[1;31mJSONDecodeError\u001B[0m: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)",
      "\nDuring handling of the above exception, another exception occurred:\n",
      "\u001B[1;31mOutputParserException\u001B[0m                     Traceback (most recent call last)",
      "Cell \u001B[1;32mIn[20], line 15\u001B[0m\n\u001B[0;32m     13\u001B[0m parser \u001B[38;5;241m=\u001B[39m PydanticOutputParser(pydantic_object\u001B[38;5;241m=\u001B[39mActor)\n\u001B[0;32m     14\u001B[0m misformatted \u001B[38;5;241m=\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m{\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mname\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124m: \u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mTom Hanks\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124m, \u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mfilm_names\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124m: [\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mForrest Gump\u001B[39m\u001B[38;5;124m'\u001B[39m\u001B[38;5;124m]}\u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[1;32m---> 15\u001B[0m \u001B[43mparser\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mparse\u001B[49m\u001B[43m(\u001B[49m\u001B[43mmisformatted\u001B[49m\u001B[43m)\u001B[49m\n",
      "File \u001B[1;32mE:\\pycharmproject\\LangChainStudyProject\\venv\\lib\\site-packages\\langchain\\output_parsers\\pydantic.py:34\u001B[0m, in \u001B[0;36mPydanticOutputParser.parse\u001B[1;34m(self, text)\u001B[0m\n\u001B[0;32m     32\u001B[0m name \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mpydantic_object\u001B[38;5;241m.\u001B[39m\u001B[38;5;18m__name__\u001B[39m\n\u001B[0;32m     33\u001B[0m msg \u001B[38;5;241m=\u001B[39m \u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mFailed to parse \u001B[39m\u001B[38;5;132;01m{\u001B[39;00mname\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m from completion \u001B[39m\u001B[38;5;132;01m{\u001B[39;00mtext\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m. Got: \u001B[39m\u001B[38;5;132;01m{\u001B[39;00me\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m\"\u001B[39m\n\u001B[1;32m---> 34\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m OutputParserException(msg, llm_output\u001B[38;5;241m=\u001B[39mtext)\n",
      "\u001B[1;31mOutputParserException\u001B[0m: Failed to parse Actor from completion {'name': 'Tom Hanks', 'film_names': ['Forrest Gump']}. Got: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)"
     ]
    }
   ],
   "source": [
    "# 导入所需的库和模块\n",
    "from langchain.prompts import PromptTemplate, ChatPromptTemplate, HumanMessagePromptTemplate\n",
    "from langchain.llms import OpenAI\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "from langchain.output_parsers import PydanticOutputParser\n",
    "from pydantic import BaseModel, Field, validator\n",
    "from typing import List\n",
    "\n",
    "# 定义一个表示演员的数据结构，包括他们的名字和他们出演的电影列表\n",
    "class Actor(BaseModel):\n",
    "    name: str = Field(description=\"name of an actor\")                   # 演员的名字\n",
    "    film_names: List[str] = Field(description=\"list of names of films they starred in\")  # 他们出演的电影列表\n",
    "\n",
    "# 定义一个查询，用于提示生成随机演员的电影作品列表\n",
    "actor_query = \"Generate the filmography for a random actor.\"\n",
    "\n",
    "# 使用`Actor`模型初始化解析器\n",
    "parser = PydanticOutputParser(pydantic_object=Actor)\n",
    "\n",
    "# 定义一个格式错误的字符串数据\n",
    "misformatted = \"{'name': 'Tom Hanks', 'film_names': ['Forrest Gump']}\"\n",
    "\n",
    "# 使用解析器尝试解析上述数据\n",
    "parser.parse(misformatted)\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T09:12:20.389649400Z",
     "start_time": "2023-08-25T09:12:20.105729Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "outputs": [
    {
     "data": {
      "text/plain": "Actor(name='Tom Hanks', film_names=['Forrest Gump'])"
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 要使misformatted字符串正确格式化，您需要确保它是一个有效的JSON字符串。这意味着您应该使用双引号（\"）而不是单引号（'）来包围键和值。以下是修改后的\n",
    "parser.parse('{\"name\": \"Tom Hanks\", \"film_names\": [\"Forrest Gump\"]}')"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T09:15:06.502993600Z",
     "start_time": "2023-08-25T09:15:06.488993500Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "outputs": [
    {
     "data": {
      "text/plain": "Actor(name='Tom Hanks', film_names=['Forrest Gump'])"
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.output_parsers import OutputFixingParser\n",
    "\n",
    "new_parser = OutputFixingParser.from_llm(parser=parser, llm=ChatOpenAI())\n",
    "new_parser.parse(misformatted)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T09:12:34.756278600Z",
     "start_time": "2023-08-25T09:12:31.928419700Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 5.5 Pydantic解析器\n",
    "此输出分析器允许用户指定任意 JSON 架构，并在 LLM 中查询符合该架构的 JSON 输出。\n",
    "\n",
    "请记住，大型语言模型是有缺陷的抽象！您需要使用具备足够容量以生成格式良好的JSON的LLM。在OpenAI系列中，DaVinci可以可靠地完成此任务，但Curie的能力已经显著下降。"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "outputs": [
    {
     "data": {
      "text/plain": "Joke(setup='Why did the chicken cross the road?', punchline='To get to the other side!')"
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 导入必要的模块和类\n",
    "from langchain.prompts import PromptTemplate, ChatPromptTemplate, HumanMessagePromptTemplate\n",
    "from langchain.llms import OpenAI\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "from langchain.output_parsers import PydanticOutputParser\n",
    "from pydantic import BaseModel, Field, validator\n",
    "from typing import List\n",
    "\n",
    "# 定义模型名称和温度（影响模型的随机性）\n",
    "model_name = 'text-davinci-003'\n",
    "temperature = 0.0\n",
    "\n",
    "# 初始化OpenAI模型\n",
    "model = OpenAI(model_name=model_name, temperature=temperature)\n",
    "\n",
    "# 定义想要的数据结构，这里是一个笑话的结构，包含设置和冷笑话\n",
    "class Joke(BaseModel):\n",
    "    setup: str = Field(description=\"question to set up a joke\")  # 笑话的设置部分\n",
    "    punchline: str = Field(description=\"answer to resolve the joke\")  # 笑话的冷笑话部分\n",
    "\n",
    "    # 使用Pydantic添加自定义验证逻辑，确保设置部分以问号结束\n",
    "    @validator('setup')\n",
    "    def question_ends_with_question_mark(cls, field):\n",
    "        if field[-1] != '?':\n",
    "            raise ValueError(\"Badly formed question!\")\n",
    "        return field\n",
    "\n",
    "# 定义一个查询，目的是提示语言模型填充上述数据结构\n",
    "joke_query = \"Tell me a joke.\"\n",
    "\n",
    "# 设置一个解析器，并将指令注入到提示模板中\n",
    "parser = PydanticOutputParser(pydantic_object=Joke)\n",
    "\n",
    "# 定义提示模板\n",
    "prompt = PromptTemplate(\n",
    "    template=\"Answer the user query.\\n{format_instructions}\\n{query}\\n\",\n",
    "    input_variables=[\"query\"],\n",
    "    partial_variables={\"format_instructions\": parser.get_format_instructions()}\n",
    ")\n",
    "\n",
    "# 格式化提示\n",
    "_input = prompt.format_prompt(query=joke_query)\n",
    "\n",
    "# 使用模型生成输出\n",
    "output = model(_input.to_string())\n",
    "\n",
    "# 使用解析器解析输出\n",
    "parser.parse(output)\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T09:19:29.659315200Z",
     "start_time": "2023-08-25T09:19:27.673920500Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "outputs": [
    {
     "data": {
      "text/plain": "Actor(name='Tom Hanks', film_names=['Forrest Gump', 'Saving Private Ryan', 'The Green Mile', 'Cast Away', 'Toy Story'])"
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 导入必要的模块和类\n",
    "from pydantic import BaseModel, Field\n",
    "from typing import List\n",
    "\n",
    "# 定义一个表示演员及其电影作品列表的数据结构\n",
    "class Actor(BaseModel):\n",
    "    name: str = Field(description=\"name of an actor\")                   # 演员的名字\n",
    "    film_names: List[str] = Field(description=\"list of names of films they starred in\")  # 他们出演的电影列表\n",
    "\n",
    "# 定义一个查询，用于提示生成随机演员的电影作品列表\n",
    "actor_query = \"Generate the filmography for a random actor.\"\n",
    "\n",
    "# 使用`Actor`模型初始化解析器\n",
    "parser = PydanticOutputParser(pydantic_object=Actor)\n",
    "\n",
    "# 定义提示模板，用于引导模型生成关于特定查询的答案\n",
    "prompt = PromptTemplate(\n",
    "    template=\"Answer the user query.\\n{format_instructions}\\n{query}\\n\",\n",
    "    input_variables=[\"query\"],\n",
    "    partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
    ")\n",
    "\n",
    "# 格式化提示\n",
    "_input = prompt.format_prompt(query=actor_query)\n",
    "\n",
    "# 使用模型生成输出\n",
    "output = model(_input.to_string())\n",
    "\n",
    "# 使用解析器解析输出\n",
    "parser.parse(output)\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T09:19:34.669842600Z",
     "start_time": "2023-08-25T09:19:33.458242200Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 5.6 重试解析器\n",
    "虽然在某些情况下，可以通过仅查看输出来修复任何解析错误，但在其他情况下则不能。\n",
    "\n",
    "例如，当输出不仅格式不正确，而且部分完成时。请考虑以下示例。"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "outputs": [],
   "source": [
    "# 导入必要的模块和类\n",
    "from langchain.prompts import PromptTemplate, ChatPromptTemplate, HumanMessagePromptTemplate\n",
    "from langchain.llms import OpenAI\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "from langchain.output_parsers import PydanticOutputParser, OutputFixingParser, RetryOutputParser\n",
    "from pydantic import BaseModel, Field, validator\n",
    "from typing import List\n",
    "\n",
    "# 定义提示模板，用于引导模型根据用户的问题提供相应的操作和操作输入\n",
    "template = \"\"\"基于用户的问题，提供应采取的操作及操作的输入。\n",
    "{format_instructions}\n",
    "问题: {query}\n",
    "回答:\"\"\"\n",
    "\n",
    "# 定义一个表示操作及其输入的数据结构\n",
    "class Action(BaseModel):\n",
    "    action: str = Field(description=\"要采取的操作\")\n",
    "    action_input: str = Field(description=\"操作的输入\")\n",
    "\n",
    "# 使用`Action`模型初始化解析器\n",
    "parser = PydanticOutputParser(pydantic_object=Action)\n",
    "\n",
    "# 定义提示模板\n",
    "prompt = PromptTemplate(\n",
    "    template=\"回答用户的问题。\\n{format_instructions}\\n{query}\\n\",\n",
    "    input_variables=[\"query\"],\n",
    "    partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
    ")\n",
    "\n",
    "# 格式化提示\n",
    "prompt_value = prompt.format_prompt(query=\"谁是马云的女朋友？\")\n",
    "\n",
    "# 定义一个不完整的回应示例\n",
    "bad_response = '{\"action\": \"search\"}'\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T09:25:43.639088200Z",
     "start_time": "2023-08-25T09:25:43.599987600Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "outputs": [
    {
     "ename": "OutputParserException",
     "evalue": "Failed to parse Action from completion {\"action\": \"search\"}. Got: 1 validation error for Action\naction_input\n  field required (type=value_error.missing)",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mValidationError\u001B[0m                           Traceback (most recent call last)",
      "File \u001B[1;32mE:\\pycharmproject\\LangChainStudyProject\\venv\\lib\\site-packages\\langchain\\output_parsers\\pydantic.py:29\u001B[0m, in \u001B[0;36mPydanticOutputParser.parse\u001B[1;34m(self, text)\u001B[0m\n\u001B[0;32m     28\u001B[0m     json_object \u001B[38;5;241m=\u001B[39m json\u001B[38;5;241m.\u001B[39mloads(json_str, strict\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m)\n\u001B[1;32m---> 29\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mpydantic_object\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mparse_obj\u001B[49m\u001B[43m(\u001B[49m\u001B[43mjson_object\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m     31\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m (json\u001B[38;5;241m.\u001B[39mJSONDecodeError, ValidationError) \u001B[38;5;28;01mas\u001B[39;00m e:\n",
      "File \u001B[1;32mE:\\pycharmproject\\LangChainStudyProject\\venv\\lib\\site-packages\\pydantic\\main.py:526\u001B[0m, in \u001B[0;36mpydantic.main.BaseModel.parse_obj\u001B[1;34m()\u001B[0m\n",
      "File \u001B[1;32mE:\\pycharmproject\\LangChainStudyProject\\venv\\lib\\site-packages\\pydantic\\main.py:341\u001B[0m, in \u001B[0;36mpydantic.main.BaseModel.__init__\u001B[1;34m()\u001B[0m\n",
      "\u001B[1;31mValidationError\u001B[0m: 1 validation error for Action\naction_input\n  field required (type=value_error.missing)",
      "\nDuring handling of the above exception, another exception occurred:\n",
      "\u001B[1;31mOutputParserException\u001B[0m                     Traceback (most recent call last)",
      "Cell \u001B[1;32mIn[31], line 2\u001B[0m\n\u001B[0;32m      1\u001B[0m \u001B[38;5;66;03m#如果我们尝试按原样解析此响应，我们将收到错误\u001B[39;00m\n\u001B[1;32m----> 2\u001B[0m \u001B[43mparser\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mparse\u001B[49m\u001B[43m(\u001B[49m\u001B[43mbad_response\u001B[49m\u001B[43m)\u001B[49m\n",
      "File \u001B[1;32mE:\\pycharmproject\\LangChainStudyProject\\venv\\lib\\site-packages\\langchain\\output_parsers\\pydantic.py:34\u001B[0m, in \u001B[0;36mPydanticOutputParser.parse\u001B[1;34m(self, text)\u001B[0m\n\u001B[0;32m     32\u001B[0m name \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mpydantic_object\u001B[38;5;241m.\u001B[39m\u001B[38;5;18m__name__\u001B[39m\n\u001B[0;32m     33\u001B[0m msg \u001B[38;5;241m=\u001B[39m \u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mFailed to parse \u001B[39m\u001B[38;5;132;01m{\u001B[39;00mname\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m from completion \u001B[39m\u001B[38;5;132;01m{\u001B[39;00mtext\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m. Got: \u001B[39m\u001B[38;5;132;01m{\u001B[39;00me\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m\"\u001B[39m\n\u001B[1;32m---> 34\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m OutputParserException(msg, llm_output\u001B[38;5;241m=\u001B[39mtext)\n",
      "\u001B[1;31mOutputParserException\u001B[0m: Failed to parse Action from completion {\"action\": \"search\"}. Got: 1 validation error for Action\naction_input\n  field required (type=value_error.missing)"
     ]
    }
   ],
   "source": [
    "#如果我们尝试按原样解析此响应，我们将收到错误\n",
    "parser.parse(bad_response)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T09:25:44.521205300Z",
     "start_time": "2023-08-25T09:25:44.459609600Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "outputs": [
    {
     "data": {
      "text/plain": "Action(action='search', action_input='query')"
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 如果我们尝试使用 来 OutputFixingParser 修复此错误，它会感到困惑 - 即，它不知道实际为操作输入放置什么。\n",
    "fix_parser = OutputFixingParser.from_llm(parser=parser, llm=ChatOpenAI())\n",
    "fix_parser.parse(bad_response)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T09:25:55.134192900Z",
     "start_time": "2023-08-25T09:25:53.509324500Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "outputs": [
    {
     "data": {
      "text/plain": "Action(action='search', action_input='马云女朋友')"
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 但是，如果我们使用 RetryOutputParser ，它将尝试使用提示和模型来修复错误。\n",
    "from langchain.output_parsers import RetryWithErrorOutputParser\n",
    "retry_parser = RetryWithErrorOutputParser.from_llm(\n",
    "    parser=parser, llm=OpenAI(temperature=0)\n",
    ")\n",
    "retry_parser.parse_with_prompt(bad_response, prompt_value)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T09:25:57.801995200Z",
     "start_time": "2023-08-25T09:25:56.114939600Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 5.7 结构化输出解析器\n",
    "当您想要返回多个字段时，可以使用此输出分析器。\n",
    "\n",
    "虽然 Pydantic/JSON 解析器功能更强大，但我们最初尝试使用仅包含文本字段的数据结构。"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "outputs": [
    {
     "data": {
      "text/plain": "{'answer': '巴黎',\n 'source': 'https://baike.baidu.com/item/%E6%B3%95%E5%9B%BD/1045'}"
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 导入必要的模块和类\n",
    "from langchain.output_parsers import StructuredOutputParser, ResponseSchema\n",
    "from langchain.prompts import PromptTemplate, ChatPromptTemplate, HumanMessagePromptTemplate\n",
    "from langchain.llms import OpenAI\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "\n",
    "# 定义响应模式，用于指导模型提供特定类型的输出\n",
    "response_schemas = [\n",
    "    ResponseSchema(name=\"answer\", description=\"回答用户的问题\"),\n",
    "    ResponseSchema(name=\"source\", description=\"回答用户问题的来源，应为一个网站。\")\n",
    "]\n",
    "\n",
    "# 使用响应模式初始化一个结构化输出解析器\n",
    "output_parser = StructuredOutputParser.from_response_schemas(response_schemas)\n",
    "\n",
    "# 获取解析器的格式指令\n",
    "format_instructions = output_parser.get_format_instructions()\n",
    "\n",
    "# 定义提示模板，用于引导模型根据用户的问题提供答案及答案的来源\n",
    "prompt = PromptTemplate(\n",
    "    template=\"尽可能回答用户的问题。\\n{format_instructions}\\n{question}\",\n",
    "    input_variables=[\"question\"],\n",
    "    partial_variables={\"format_instructions\": format_instructions}\n",
    ")\n",
    "\n",
    "# 初始化OpenAI模型，温度设置为0（生成的回答将更加确定，少有随机性）\n",
    "model = OpenAI(temperature=0)\n",
    "\n",
    "# 格式化提示，这里的问题是“法国的首都是什么？”\n",
    "_input = prompt.format_prompt(question=\"法国的首都是什么？\")\n",
    "\n",
    "# 使用模型生成输出\n",
    "output = model(_input.to_string())\n",
    "\n",
    "# 使用解析器解析输出\n",
    "output_parser.parse(output)\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T09:30:47.654631300Z",
     "start_time": "2023-08-25T09:30:44.614845200Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "outputs": [
    {
     "data": {
      "text/plain": "{'answer': '法国的首都是巴黎。',\n 'source': 'https://zh.wikipedia.org/wiki/%E5%B7%B4%E9%BB%8E'}"
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 导入必要的模块和类\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "from langchain.prompts import ChatPromptTemplate, HumanMessagePromptTemplate\n",
    "\n",
    "# 初始化聊天模型，温度设置为0（生成的回答将更加确定，少有随机性）\n",
    "chat_model = ChatOpenAI(temperature=0)\n",
    "\n",
    "# 定义聊天提示模板，该模板包含一系列的消息对象\n",
    "# 这里我们只定义一个消息，该消息提示模型尽可能地回答用户的问题\n",
    "prompt = ChatPromptTemplate(\n",
    "    messages=[\n",
    "        HumanMessagePromptTemplate.from_template(\"尽可能回答用户的问题。\\n{format_instructions}\\n{question}\")\n",
    "    ],\n",
    "    input_variables=[\"question\"],\n",
    "    partial_variables={\"format_instructions\": format_instructions}\n",
    ")\n",
    "\n",
    "# 格式化提示，这里的问题是“法国的首都是什么？”\n",
    "_input = prompt.format_prompt(question=\"法国的首都是什么？\")\n",
    "\n",
    "# 使用聊天模型生成输出\n",
    "output = chat_model(_input.to_messages())\n",
    "\n",
    "# 使用解析器解析输出的内容\n",
    "output_parser.parse(output.content)\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2023-08-25T09:31:29.272627Z",
     "start_time": "2023-08-25T09:31:26.919895800Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [],
   "metadata": {
    "collapsed": false
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
